package com.ms.game.bank.db;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;

import org.hibernate.Session;

import com.ms.game.bank.BankMoneyChangeWay;
import com.ms.game.bank.CashChangeWay;
import com.ms.game.bank.VipChangeWay;
import com.ms.game.bank.container.BankInfoBin;
import com.ms.game.bank.message.BankBuyFeeResponse;
import com.ms.game.common.container.LevelInfoBin;
import com.ms.game.common.container.LevelInfoBinUtil;
import com.ms.game.common.container.LevelUpInfo;
import com.ms.game.purchase.bin.PurchaseType;
import com.ms.game.rebate.RebateModifyStatus;
import com.ms.game.rebate.RebateType;
import com.ms.game.rebate.db.RebateLogModel;
import com.ms.player.Player;
import com.ms.player.PlayerAttributeType;
import com.ms.player.UpdateAttributeList;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.analysisgroup.AnalysisGroupProcessor;
import com.ms.service.module.analysisgroup.CoinExpenditureWay;
import com.ms.service.module.datacenterlite.CentralAsyncCommand;
import com.ms.service.module.zone.module.BasicZoneModule;
import com.xpec.c4.db.dao.PlayerDAO;
import com.xpec.c4.db.dao.PlayerLevelCalculator;
import com.xpec.c4.db.hibernate.manager.HibernateLogManager;
import com.xpec.c4.db.model.PlayerModel;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.game.utility.GUIDType;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.message.MessageAction;

public class updateAccountWeeklyCashDCLAsysn extends CentralAsyncCommand {

	private static final long serialVersionUID = -8827471796872148007L;

	public GUID accountID;

	public GUID playerID;

	public GUID sessionID;

	public String playerName;
	
	public boolean robot;

	public long afterAccountCash;

	public long cashPoint;

	public boolean isFirstChange;
	
	public int userType;

	/**
	 * 帳號點數是否足夠
	 */
	private boolean isEnough;

	/**
	 * vip等級
	 */
	private int afterVip;

	/**
	 * 改變後vip經驗值
	 */
	private long afterVipExp;

	/**
	 * 改變前vip等級
	 */
	private int beforeVipLv;

	/** 改變之後的銀行幣 */
	private BigDecimal afterBankCoin;

	/** 改變之後的包月結束時間 */
	private long monthlyFeeEndTime;

	private long monthlyAwardTime;

	/** 改變之後的包週結束時間 */
	private long weeklyFeeEndTime;

	private long weeklyAwardTime;

	public int buyFeeType;
	
	/**
	 * 改變後的角色等級
	 */
	private int beforeLv;
	
	/**
	 * 改變後的角色等級
	 */
	private int afterLv;
	
	/**
	 * 改變後的角色經驗
	 */
	private BigDecimal afterExp;

	private UpdateAttributeList updateAttributeList;
	
	/**
	 * 銀行增加的金幣
	 */
	private BigDecimal bankGoldChangeValueForAnalysis;
	
	private boolean isSave = true;
	
	private boolean isCashLoad = true;
	
	@Override
	public void asyncExecute() throws Exception {
		// ////
		String orderId = GUIDFactory.createUUID(GUIDType.TYPE_CASH_POINT).toString();
		 updateAttributeList = new UpdateAttributeList();
		PlayerModel model = PlayerDAO.loadPlayerModelByGuid(playerID);
		// TODO kevin loadAccountCash [v] 包月
		Object[] cashOb = BankDAO.loadAccountCashPoint(accountID);
		
		if (cashOb == null) {
			isCashLoad = false;
			return;
		}
		
		long beforeAccountCash = (long) cashOb[0];
		if (isFirstChange) {
			isFirstChange = !(boolean) cashOb[1];
		}
		afterAccountCash = beforeAccountCash - cashPoint;
		if (afterAccountCash < 0) {
			isEnough = false;
			return;
		} else {
			isEnough = true;
		}

		
		GameUtility.writeCashUpdateConsoleLog("updateAccountCashDCLAsysn.asyncExecute()", accountID.toString(), beforeAccountCash, cashPoint, afterAccountCash);

		// account扣點
		isSave = BankDAO.UpdateAccountCashPoint(accountID, afterAccountCash, isFirstChange);		
		if(!isSave) {
			GameUtility.writeCashUpdateConsoleLog("updateAccountCashDCLAsysn.asyncExecute() DB Operation Fail", accountID.toString(), beforeAccountCash, cashPoint, afterAccountCash);
			return;
		}
			
		// account扣點後的log 直接寫入log
		Session sessionlog = HibernateLogManager.txBegin();
		CashLogModel cashLogModel = new CashLogModel();
		cashLogModel.setOrderId(orderId);
		cashLogModel.setAccountId(accountID.toString());
		cashLogModel.setPlayerId(playerID.toString());
		cashLogModel.setPlayerName(playerName);
		cashLogModel.setCashBeforeChange(beforeAccountCash);
		cashLogModel.setCashChangeValue(cashPoint);
		cashLogModel.setCashAfterChange(afterAccountCash);
		cashLogModel.setGoldBeforeChange(model.getGoldCoin());
		cashLogModel.setGoldChangeValue(BigDecimal.ZERO);
		cashLogModel.setGoldAfterChange(model.getGoldCoin());
		if (buyFeeType == PurchaseType.MONTH) {
			cashLogModel.setChangeWay(CashChangeWay.SUB_MONTHLY_FEE_PAY.getId());
			cashLogModel.setChangeWayDesc(CashChangeWay.SUB_MONTHLY_FEE_PAY.getDesc());
		} else if (buyFeeType == PurchaseType.WEEK) {
			cashLogModel.setChangeWay(CashChangeWay.SUB_WEEKLY_FEE_PAY.getId());
			cashLogModel.setChangeWayDesc(CashChangeWay.SUB_WEEKLY_FEE_PAY.getDesc());
		}
		sessionlog.save(cashLogModel);
		HibernateLogManager.txCommitFailRollbackClearSession();

		// bank gold 兌換變化
		BigDecimal bankGoldBeforeChange = model.getBankGoldCoin();
		BigDecimal bankGoldChangeValue;
		bankGoldChangeValue = new BigDecimal(BankInfoBin.getInstance().getFeeInfos().get(buyFeeType).getFeeFirstPay());
		BigDecimal bankGoldAfterChange = bankGoldBeforeChange.add(bankGoldChangeValue);
		afterBankCoin = bankGoldAfterChange;

		// 把包月配發的錢加到bank
		BankDAO.UpdateBankMoney(GUID.parseUUID(model.getGuid()), bankGoldChangeValue);

		// 寫bank log
		BankLogModel bankLogModel = new BankLogModel();
		bankLogModel.setOrderId(orderId);
		bankLogModel.setAccountId(model.getAccountId().toString());
		bankLogModel.setPlayerId(model.getGuid().toString());
		bankLogModel.setPlayerName(playerName);
		if (buyFeeType == PurchaseType.MONTH) {
			bankLogModel.setChangeWay(BankMoneyChangeWay.ADD_MONTHLY_FEE_FIRST_PAY.getId());
			bankLogModel.setChangeWayDesc(BankMoneyChangeWay.ADD_MONTHLY_FEE_FIRST_PAY.getDesc());
		} else if (buyFeeType == PurchaseType.WEEK) {
			bankLogModel.setChangeWay(BankMoneyChangeWay.ADD_WEEKLY_FEE_FIRST_PAY.getId());
			bankLogModel.setChangeWayDesc(BankMoneyChangeWay.ADD_WEEKLY_FEE_FIRST_PAY.getDesc());
		}
		bankLogModel.setBankGoldAfterChange(bankGoldAfterChange);
		bankLogModel.setBankGoldChangeValue(bankGoldChangeValue);
		bankLogModel.setBankGoldBeforeChange(bankGoldBeforeChange);
		getCurrentModuleServer().saveDbLog(bankLogModel);

		// 寫回饋金log
		RebateLogModel rebateLogModel = new RebateLogModel();
		rebateLogModel.setOrderId(orderId);
		rebateLogModel.setBelongsDate(GameUtility.getCurrentDate());
		rebateLogModel.setStatus(RebateModifyStatus.HAVE_RECEIVED);
		rebateLogModel.setTotalRebateCoin(bankGoldChangeValue);
		rebateLogModel.setPlayerId(playerID.toString());
		if (buyFeeType == PurchaseType.MONTH) {
			rebateLogModel.setType(RebateType.MONTHLY_FEE_FIREST_PAY.getId());
			rebateLogModel.setTypeDesc(RebateType.MONTHLY_FEE_FIREST_PAY.getDesc());
		} else if (buyFeeType == PurchaseType.WEEK) {
			rebateLogModel.setType(RebateType.WEEKLY_FEE_FIREST_PAY.getId());
			rebateLogModel.setTypeDesc(RebateType.WEEKLY_FEE_FIREST_PAY.getDesc());
		}
		rebateLogModel.setPlayerName(model.getName());
		getCurrentModuleServer().saveDbLog(rebateLogModel);

		// 更新玩家包月時間
		isSave = BankDAO.UpdatePlayerWeeklyFee(model, buyFeeType);
		weeklyAwardTime = model.getWeeklyAwardTime().getTime();
		weeklyFeeEndTime = model.getWeeklyFeeEndTime().getTime();

		// player VIP經驗值
		ArrayList<LevelUpInfo> levelInfo = LevelInfoBin.getInstance().getVipLevelUpInfoList();

		// 改變前
		beforeVipLv = model.getVip();
		long beforeVipExp = model.getVipExp();
		if (beforeVipLv < levelInfo.size()) {
			// Vip未滿才檢查
			model.setVipExp(model.getVipExp() + cashPoint);
			for (int index = 0; index < levelInfo.size(); index++) {
				LevelUpInfo info = levelInfo.get(index);
				if (info.getNeedExp() > model.getVipExp()) {
					model.setVip(info.getLevel() - 1);
					break;
				}
				// 最高等級vip
				if (info.getLevel() == levelInfo.size() + 1) {
					model.setVip(info.getLevel());
				}
			}

			VipLogModel vipLogModel = new VipLogModel();
			vipLogModel.setOrderId(orderId);
			vipLogModel.setAccountId(accountID.toString());
			vipLogModel.setPlayerId(playerID.toString());
			vipLogModel.setPlayerName(playerName);
			vipLogModel.setUserType(model.getUserType());
			vipLogModel.setVipBefore(beforeVipLv);
			vipLogModel.setVipAfter(model.getVip());
			vipLogModel.setExpBeforeChange(beforeVipExp);
			vipLogModel.setExpChangeValue(cashPoint);
			vipLogModel.setExpAfterChange(model.getVipExp());
			if (buyFeeType == PurchaseType.MONTH) {
				vipLogModel.setChangeWay(VipChangeWay.ADD_MONTHLY_FEE_PAY.getId());
				vipLogModel.setChangeWayDesc(VipChangeWay.ADD_MONTHLY_FEE_PAY.getDesc());
			} else if (buyFeeType == PurchaseType.WEEK) {
				vipLogModel.setChangeWay(VipChangeWay.ADD_WEEKLY_FEE_PAY.getId());
				vipLogModel.setChangeWayDesc(VipChangeWay.ADD_WEEKLY_FEE_PAY.getDesc());
			}
			getCurrentModuleServer().saveDbLog(vipLogModel);
		}
		afterVip = model.getVip();
		afterVipExp = model.getVipExp();

		
		beforeLv = model.getLevel();
		//第一次轉點的時候，要把角色等級也升到一
		if(beforeVipLv == 0 && afterVip > 0 && beforeLv == 0){
		 	afterLv = 1;
		 	model.setExp(LevelInfoBinUtil.getExpByLevel(beforeLv, (afterLv - beforeLv)));
		 	afterExp = model.getExp();
			updateAttributeList.addUpdateValue(PlayerAttributeType.LEVEL, afterLv);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP, afterExp);
			
			HashMap<String, Long> expInfos = LevelInfoBinUtil.getExpInfos(afterExp);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_IN_CURRENT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_IN_CURRENT_LEVEL));
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_TO_NEXT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_TO_NEXT_LEVEL));
		}
		
		if (isSave) {
			updateAttributeList.addUpdateValue(PlayerAttributeType.VIP, afterVip);
			updateAttributeList.addUpdateValue(PlayerAttributeType.VIP_EXP, afterVipExp);

			if (isFirstChange)
				updateAttributeList.addUpdateValue(PlayerAttributeType.STORE_REWARD_CONTINUOUS_LOGIN_COUNT, 1);

			// 更新玩家vip經驗和等級
			// BankDAO.UpdatePlayerVip(playerID, afterVip, afterVipExp,isFirstChange);

			PlayerDAO.updatePlayerFromAttrList(playerID.toString(), updateAttributeList.getUpdateList(), userType);
			
			bankGoldChangeValueForAnalysis = bankGoldChangeValue;
		}
	}

	@Override
	public void callBackExecute(Object... userData) throws Exception {

		BankBuyFeeResponse response = new BankBuyFeeResponse();
		BasicZoneModule module = (BasicZoneModule) userData[0];
		Player playerData = (Player) userData[1];

		if(!isCashLoad){
			// load cash point 失敗
			response.errorCode = ErrorCode.DB_OPERATION_FAIL;
			MessageAction.sendMessage(sessionID, MessageTypes.S_BANK_BUY_FEE_RESPONSE, response);
			return;
		}

		if (!isEnough) {
			// 帳號點數不足
			response.errorCode = ErrorCode.CASH_POINT_NOT_ENOUGH;
			MessageAction.sendMessage(sessionID, MessageTypes.S_BANK_BUY_FEE_RESPONSE, response);
			return;
		}
		
		if(!isSave){
			//存失敗
			response.errorCode = ErrorCode.DB_OPERATION_FAIL;
			MessageAction.sendMessage(sessionID, MessageTypes.S_BANK_BUY_FEE_RESPONSE, response);
			return;
		}

		// 更新zone上的資料 (其實 playerDataZone = playerData -.-)
		Player playerDataZone = module.getZone().getPlayer(playerID);
		if (playerDataZone != null) {
			playerDataZone.setVip(afterVip);
			playerDataZone.setVipExp(afterVipExp);
			if(beforeVipLv == 0 && afterVip > 0 && beforeLv == 0){
				playerDataZone.setLevel(afterLv);
				playerDataZone.setExp(afterExp);
			}
			playerDataZone.setWeeklyAwardTime(weeklyAwardTime);
			playerDataZone.setWeeklyFeeEndTime(weeklyFeeEndTime);
			playerDataZone.setBankGoldCoin(afterBankCoin);
			if (isFirstChange) {
				playerData.setHaveFirstStoreCharacter(true);
				playerData.setStoreRewardContinuousLoginCount(1);
			}
		}
		
		
		updateAttributeList.sendToClient(playerData.getGuid(), sessionID, playerData.getUserType());
		
		response.errorCode = ErrorCode.SUCCESS;
		response.bankGold = afterBankCoin.toString();
		response.goldCoin = playerData.getGoldCoin().toString();
		response.accountCashPoint = afterAccountCash;
		response.buyFeeEndTime = weeklyFeeEndTime;
		response.vip = afterVip;
		response.vipExp = afterVipExp;
		MessageAction.sendMessage(sessionID, MessageTypes.S_BANK_BUY_FEE_RESPONSE, response);

	
		if(isFirstChange){
			MessageAction.sendMessage(sessionID, MessageTypes.S_FIRST_STORE_NOTIFY, "");
		}
		
		//送到統計C幣支出
		AnalysisGroupProcessor.sendCoinExpenditureToAnalysis(CoinExpenditureWay.WEEK_REWARD, bankGoldChangeValueForAnalysis);
		
	}

}
